package de.nordakademie.wpk.share.ui.view.chartview;

import java.awt.BasicStroke;
import java.awt.Color;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

import com.jensoft.sw2d.core.glyphmetrics.GlyphMetric;
import com.jensoft.sw2d.core.glyphmetrics.GlyphMetricsFactory;
import com.jensoft.sw2d.core.glyphmetrics.StylePosition;
import com.jensoft.sw2d.core.glyphmetrics.painter.fill.GlyphFill;
import com.jensoft.sw2d.core.glyphmetrics.painter.marker.RoundMarker;
import com.jensoft.sw2d.core.palette.FilPalette;
import com.jensoft.sw2d.core.palette.InputFonts;
import com.jensoft.sw2d.core.palette.RosePalette;
import com.jensoft.sw2d.core.palette.TangoPalette;
import com.jensoft.sw2d.core.plot.serie.Serie2D;
import com.jensoft.sw2d.core.plot.serie.SerieFactory;
import com.jensoft.sw2d.core.plugin.area.AreaCurve;
import com.jensoft.sw2d.core.plugin.area.AreaCurveFactory;
import com.jensoft.sw2d.core.plugin.area.AreaCurveView;
import com.jensoft.sw2d.core.plugin.area.painter.draw.AreaDefaultDraw;
import com.jensoft.sw2d.core.plugin.area.painter.fill.AreaGradientFill;
import com.jensoft.sw2d.core.plugin.band.BandPlugin;
import com.jensoft.sw2d.core.plugin.band.BandPlugin.BandOrientation;
import com.jensoft.sw2d.core.plugin.band.manager.DynBandManager;
import com.jensoft.sw2d.core.plugin.band.painter.BandPalette;
import com.jensoft.sw2d.core.plugin.gradient.GradientPlugin;
import com.jensoft.sw2d.core.plugin.gradient.Night;
import com.jensoft.sw2d.core.plugin.grid.Grid.GridOrientation;
import com.jensoft.sw2d.core.plugin.grid.GridPlugin;
import com.jensoft.sw2d.core.plugin.grid.manager.DynamicGridManager;
import com.jensoft.sw2d.core.plugin.legend.Legend;
import com.jensoft.sw2d.core.plugin.legend.LegendConstraints;
import com.jensoft.sw2d.core.plugin.legend.LegendConstraints.LegendAlignment;
import com.jensoft.sw2d.core.plugin.legend.LegendConstraints.LegendPosition;
import com.jensoft.sw2d.core.plugin.legend.LegendFactory;
import com.jensoft.sw2d.core.plugin.legend.LegendPlugin;
import com.jensoft.sw2d.core.plugin.metrics.axis.AxisMetricsPlugin.Axis;
import com.jensoft.sw2d.core.plugin.metrics.axis.AxisMilliMetrics;
import com.jensoft.sw2d.core.plugin.zoom.wheel.ZoomWheelPlugin;
import com.jensoft.sw2d.core.window.Window2D;

import de.nordakademie.wpk.share.core.data.Share;

/**
 * @author Bent Juergensen
 * 
 */
public class ChartView extends ViewFrame {

	private double[] xValues;
	private double[] yValues;
	private int maxCourse;
	private int minCourse;
	private AreaCurve areaCurve;
	private HashMap<GregorianCalendar, BigDecimal> dataMap;
	private boolean corruptData = false;
	private DataFetcher df;

	private static final long serialVersionUID = 2206814600576803890L;

	public ChartView(Share share) {
		df = new DataFetcher(this, share);
		if (df.initFetchData()) {
			maxCourse = df.getMaxCourse();
			minCourse = df.getMinCourse();
			show(createGraph(), share.getName());
		} else
			corruptData = true;
	}

	/**
	 * 
	 * @param share
	 * @return boolean (true if okay, false if corrupt data is delivered)
	 */
	public static boolean createChartView(Share share) {
		ChartView chartView = new ChartView(share);
		if (chartView.corruptData)
			return false;
		chartView.pack();
		chartView.setSize(1250, 600);
		return true;
	}

	private Graph2d createGraph() {
		// maxCourse sets the y-axis of the chart to a reasonable value
		AreaCurveView areaView = AreaCurveFactory.createCompatibleView(1.1, xValues.length, (minCourse*0.9) , maxCourse + (0.1*maxCourse));
		areaView.getWindow().setThemeColor(new Color(30, 30, 30));

		Serie2D serie = SerieFactory.createInterpolateSerieFromArray(xValues, yValues, 0.1);

		areaCurve = new AreaCurve(serie);
		areaCurve.setAreaDraw(new AreaDefaultDraw(RosePalette.BORDEAUX, new BasicStroke(2.5f)));
		areaCurve.setThemeColor(Color.DARK_GRAY);
		areaCurve.setAreaFill(new AreaGradientFill());
		areaCurve.setAreaBase(0);
		areaView.addAreaCurve(areaCurve);
		
		setDateMarkerOnCurve();

		// Set legend on axis
		LegendPlugin legendPlugin = new LegendPlugin();
		areaView.registerPlugin(legendPlugin);

		Legend l1 = LegendFactory.createLegend("30-Tage Ansicht", InputFonts
				.getElements(22), new Color(120, 120, 120), new Color(120, 120,
				120), new LegendConstraints(LegendPosition.North, 0.6f,
				LegendAlignment.Middle));
		legendPlugin.addLegend(l1);

		Legend l2 = LegendFactory.createLegend("Kurswert", InputFonts
				.getElements(15), new Color(120, 120, 120), new Color(120, 120,
				120), new LegendConstraints(LegendPosition.North, 0.3f,
				LegendAlignment.Left));
		legendPlugin.addLegend(l2);

		Legend l3 = LegendFactory.createLegend("Tage", InputFonts
				.getElements(15), new Color(120, 120, 120), new Color(120, 120,
				120), new LegendConstraints(LegendPosition.South, 0.4f,
				LegendAlignment.Rigth));
		legendPlugin.addLegend(l3);

		ZoomWheelPlugin wheelPlugin = new ZoomWheelPlugin();
		areaView.registerPlugin(wheelPlugin);

		DynBandManager dbm = new DynBandManager(BandOrientation.Horizontal, 0, 2.5);
		BandPlugin bandPlugin = new BandPlugin(dbm);
		BandPalette bp = new BandPalette();
		bp.addPaint(new Color(255, 255, 255, 40));
		bp.addPaint(new Color(40, 40, 40, 40));
		dbm.setBandPalette(bp);
		bandPlugin.setAlpha(0.3f);
		areaView.registerPlugin(bandPlugin);

		GradientPlugin night = new Night();
		night.setAlpha(1f);
		areaView.registerPlugin(night);

		// create horizontal manager with reference and grid interval
		DynamicGridManager hdgm = new DynamicGridManager(GridOrientation.Horizontal, 0, 2.5);
		hdgm.setGridColor(new Color(59, 89, 152, 100));
		GridPlugin horizontalGrid = new GridPlugin(hdgm);
		areaView.registerPlugin(horizontalGrid);

		// create vertical manager with reference and grid interval
		DynamicGridManager vdgm = new DynamicGridManager(GridOrientation.Vertical, 0, 2.5);
		vdgm.setGridColor(new Color(59, 89, 152, 100));
		GridPlugin verticalGrid = new GridPlugin(vdgm);
		areaView.registerPlugin(verticalGrid);

		Window2D w2d = areaView.getWindow();
		// unregister original axis for a more detailed configuration of the new y-axis
		w2d.unregisterPlugin(areaView.getAxisMiliMetricsX());
		w2d.unregisterPlugin(areaView.getAxisMiliMetricsY());

		// the following code fixes a bug in current sw2d version
		AxisMilliMetrics axisMiliMetricsY = new AxisMilliMetrics(0, Axis.AxisWest);
		axisMiliMetricsY.setMajor(1);
		axisMiliMetricsY.setMedian(0.5);
		axisMiliMetricsY.setMinor(0.1);
		w2d.registerPlugin(axisMiliMetricsY);

		Graph2d view = new Graph2d();
		view.setView2D(areaView);
		return view;
	}

	private void setDateMarkerOnCurve() {
		Double i = (double)dataMap.size()-1;
		LinkedHashMap<Double, GlyphMetric> marker = new LinkedHashMap<Double, GlyphMetric>();
		for (Entry<GregorianCalendar, BigDecimal> e : dataMap.entrySet()) {
			GregorianCalendar d = e.getKey();
			if (i < (double) xValues.length && i >= 2.0) {
				GlyphMetric gm = GlyphMetricsFactory.createGlyphMetrics(i);
				marker.put(i, gm);
				marker.get(i).setGlyphMetricFill(
						new GlyphFill(FilPalette.GRAY2, FilPalette.GRAY2));
				marker.get(i).setFont(
						InputFonts.getFont(InputFonts.SANSATION_BOLD, 12));
				marker.get(i).setMetricsLabel(
						d.get(Calendar.DAY_OF_MONTH) + "." + (d.get(Calendar.MONTH) + 1) + ".");
				marker.get(i).setStylePosition(StylePosition.Default);
				marker.get(i).setDivergence(15);
				marker.get(i).setGlyphMetricMarkerPainter(new RoundMarker(TangoPalette.ORANGE1));
				areaCurve.addMetricsLabel(marker.get(i));
				i--;
			}
		}
	}

	protected double[] getxValues() {
		return xValues;
	}

	protected void setxValues(double[] xValues) {
		this.xValues = xValues;
	}

	protected double[] getyValues() {
		return yValues;
	}

	protected void setyValues(double[] yValues) {
		this.yValues = yValues;
	}
	
	protected void setDataMap(HashMap<GregorianCalendar, BigDecimal> dataMap) {
		this.dataMap = dataMap;
	}

}
